package com.xiaoyu.base.data;

import android.app.Activity;
import android.text.Html;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;

import com.xiaoyu.base.log.BaseLogClient;

import in.srain.cube.util.UTUtil;
import in.srain.cube.util.log.LogEvent;
import in.srain.cube.util.StringUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;

import in.srain.cube.request.JsonData;

public class DocData {

    private final static String EMPTY = "";
    private static DocData sInstance;

    private Map<String, Doc> mDocMap = new ConcurrentHashMap<>();

    private DocData() {
    }

    public static synchronized DocData getInstance() {
        if (sInstance == null) {
            sInstance = new DocData();
        }
        return sInstance;
    }

    private static void warning(Doc doc) {
        Exception exception = new RuntimeException("doc warning: " + doc == null ? "" : doc.mDoc);
        exception.printStackTrace();
    }

    private static void warning(Doc doc, String key) {
        Exception exception = new RuntimeException("doc warning: " + doc == null ? "" : doc.mDoc + ",input key is missing:" + key);
        exception.printStackTrace();
    }

    private static void docNotFoundLogEvent(String key) {
        LogEvent logEvent = new LogEvent("doc_key_not_found");
        logEvent.putData("key", key);
        BaseLogClient.Companion.getInstance().addLog(logEvent);
    }

    public void updateDocList(JsonData listRaw) {
        if (mDocMap == null) {
            return;
        }
        mDocMap.clear();
        final List<JsonData> rawList = listRaw.toList();
        for (int i = 0; i < rawList.size(); i++) {
            JsonData item = rawList.get(i);
            mDocMap.put(item.optString("key"), new Doc(item));
        }
    }

    public void setText(Activity activity, int id, String key) {
        setText(activity.findViewById(id), key);
    }

    public void setText(Activity activity, int id, String key, String defaultDoc) {
        setText(activity.findViewById(id), key, defaultDoc);
    }

    public void setText(View view, int id, String key) {
        setText(view.findViewById(id), key);
    }

    public void setText(View view, int id, String key, String defaultDoc) {
        setText(view.findViewById(id), key, defaultDoc);
    }

    public void setText(View view, String key) {
        setText(view, key, "");
    }

    public void setText(View view, String key, String defaultDoc) {
        TextView textView = (TextView) view;
        if (textView == null) {
            return;
        }
        textView.setText(StringUtil.defaultIfEmpty(getDoc(key).toString(), defaultDoc));
    }

    public CharSequence[] getDocs(String... keys) {
        CharSequence[] docs = new String[keys.length];
        for (int i = 0; i < keys.length; i++) {
            docs[i] = getDoc(keys[i]);
        }
        return docs;
    }

    public CharSequence getDoc(String key) {
        return getDoc(key, EMPTY);
    }

    public CharSequence getDoc(String key, String defaultDoc) {
        if (!mDocMap.containsKey(key)) {
            docNotFoundLogEvent(key);
            return defaultDoc;
        }
        Doc doc = mDocMap.get(key);
        if (doc == null) {
            docNotFoundLogEvent(key);
            return defaultDoc;
        }
        if (doc.mDocKeys.length > 0) {
            docNotFoundLogEvent(key);
            warning(doc);
            return defaultDoc;
        }
        return doc.render(null);
    }

    /**
     * @deprecated Please use {@link #getDocWithParis} instead.
     */
    @Deprecated
    public CharSequence getDoc(String docKey, String... nameAndValue) {
        Map<String, Pair> payload = null;
        if (null != nameAndValue && nameAndValue.length > 0) {
            payload = new HashMap<>();
            for (int i = 0; i < nameAndValue.length; i += 2) {
                String key = nameAndValue[i];
                String val = "";
                if (i + 1 < nameAndValue.length) {
                    val = nameAndValue[i + 1];
                }
                payload.put(key, new Pair(key, val, EMPTY));
            }
        }
        return getDocWithMap(docKey, payload);
    }

    public CharSequence getDocWithParis(String docKey, Pair... nameAndValue) {
        return getDocWithParis(docKey, EMPTY, nameAndValue);
    }

    public CharSequence getDocWithParis(String docKey, String defaultDoc, Pair... nameAndValue) {
        Map<String, Pair> payload = null;
        if (null != nameAndValue && nameAndValue.length > 0) {
            payload = new HashMap<>();
            for (int i = 0; i < nameAndValue.length; i += 1) {
                Pair pair = nameAndValue[i];
                payload.put(pair.getKey(), pair);
            }
        }
        return getDocWithMap(docKey, payload, defaultDoc);
    }

    private CharSequence getDocWithMap(String key, Map<String, Pair> payload) {
        return getDocWithMap(key, payload, EMPTY);
    }

    private CharSequence getDocWithMap(String key, Map<String, Pair> payload, String defaultDoc) {
        if (!mDocMap.containsKey(key)) {
            docNotFoundLogEvent(key);
            return defaultDoc;
        }
        final Doc doc = mDocMap.get(key);
        if (doc == null) {
            docNotFoundLogEvent(key);
            return defaultDoc;
        }
        return doc.render(payload);
    }

    private static class Doc {

        private String mDoc;
        private String[] mDocKeys;
        private boolean mIsHtml;

        private Doc(JsonData item) {
            mDoc = item.optString("doc");
            mIsHtml = TextUtils.equals("html", item.optString("type"));
            if (item.optJson("doc_keys").length() > 0) {
                List<String> keys = item.optJson("doc_keys").asList();
                mDocKeys = keys.toArray(new String[0]);
            } else {
                mDocKeys = new String[0];
            }
        }

        private CharSequence render(Map<String, Pair> payload) {
            if (mDocKeys == null || mDocKeys.length == 0) {
                if (mIsHtml) {
                    return Html.fromHtml(mDoc);
                }
                return mDoc;
            }

            if (payload == null || payload.size() < mDocKeys.length) {
                warning(this);
                return EMPTY;
            }

            String doc = mDoc;
            for (int i = 0; i < mDocKeys.length; i++) {
                String key = mDocKeys[i];
                if (!payload.containsKey(key)) {
                    warning(this, key);
                }
                String string = "\\{\\$" + mDocKeys[i] + "\\}";
                String replacement = Matcher.quoteReplacement(String.valueOf(payload.get(key) != null ? (payload.get(key).getmValue() == null ? payload.get(key).getDefaultValue() : payload.get(key).getmValue()) : EMPTY));
                doc = doc.replaceAll(string, replacement);
            }
            if (mIsHtml) {
                return Html.fromHtml(doc);
            }
            return doc;
        }
    }

    public static class Pair {
        private String mKey;
        private String mValue;
        private String mDefaultValue;

        public Pair(String mKey, String mValue, String mDefaultValue) {
            this.mKey = mKey;
            this.mValue = mValue;
            this.mDefaultValue = mDefaultValue;
        }

        public String getDefaultValue() {
            return mDefaultValue;
        }

        public String getmValue() {
            return mValue;
        }

        public String getKey() {
            return mKey;
        }
    }
}
